
#include <cstdio>
#include <ctime>

#include <BMap>
#include <BIcon>
#include <BImage>
#include <BFile>
#include <BFolder>
#include <BEntry>
#include <BDisk>
#include <BScreen>
#include <BNetwork>
#include <BSystem>
#include "member_BScreen.h"
#include "member_BNetwork.h"
#include "member_BDisk.h"
#include "IGlobal.h"

using namespace BWE;

BArray<BDiskHolder> disks;
BArray<BScreenHolder> screens;
BArray<BNetworkHolder> networks;

#ifdef linux
#include <unistd.h>
#include <mntent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <X11/Xlib.h>
#include <X11/keysymdef.h>
#include <X11/XKBlib.h>
#include <X11/Xatom.h>
#include <dirent.h>
#include <pwd.h>

#define MAX_PATH 1024
#define MAX_THEMES 20
#define MAX_DIRS 50

struct IconTheme
{
	BString name;
	BString inherits;
	BString directories;
};
bool read_theme_index(const BString& theme_path, IconTheme& theme_info)
{
	BString index_path;
	index_path << theme_path << "/index.theme";

	BString text;
	if(!BFile::Load(index_path, text))
		return 0;

	BString line;
	int in_icon_theme = 0;
	int pos = text.find("[Icon Theme]");
	while(pos < text.size())
	{
		pos = text.line(line, pos);
		if (in_icon_theme && line[0] == '[')
			break;
		if (line.beginWith("Name="))
		{
			theme_info.name = line;
			theme_info.name -= "Name=";
			continue;;
		}
		if (line.beginWith("Inherits="))
		{
			theme_info.inherits = line;
			theme_info.inherits -= "Inherits=";
			continue;;
		}
		if (line.beginWith("Directories="))
		{
			theme_info.directories = line;
			theme_info.directories -= "Directories=";
			continue;;
		}
	}

	return true;
}

const BString& GetMimeMap(const BString& filePath)
{
	static BMap<BString, BString> mime_map;
	if (mime_map.empty())
	{
		mime_map["dir"] = "folder";
		mime_map["txt"] = "text-x-generic";
		mime_map["pdf"] = "application-pdf";
		mime_map["png"] = "image-png";
		mime_map["jpg"] = "image-jpeg";
		mime_map["jpeg"] = "image-jpeg";
		mime_map["gif"] = "image-gif";
		mime_map["svg"] = "image-svg+xml";
		mime_map["mp3"] = "audio-x-generic";
		mime_map["mp4"] = "video-x-generic";
		mime_map["avi"] = "video-x-generic";
		mime_map["zip"] = "application-zip";
		mime_map["tar"] = "application-x-tar";
		mime_map["gz"] = "application-x-gzip";
		mime_map["deb"] = "application-x-deb";
		mime_map["html"] = "text-html";
		mime_map["xml"] = "text-xml";
		mime_map["h"] = "text-x-chdr";
		mime_map["c"] = "text-x-csrc";
		mime_map["cpp"] = "text-x-c++src";
		mime_map["cs"] = "text-x-csharp";
		mime_map["bs"] = "text-x-bscript";
		mime_map["py"] = "text-x-python";
		mime_map["js"] = "text-x-javascript";
		mime_map.def() = "text-x-generic";
	}
	
	struct stat st;
	if (stat(filePath.cstr(), &st) != 0)
		return mime_map.def();

	const char* ext = filePath.ext();
	if (S_ISDIR(st.st_mode))
		ext = "dir";

	return mime_map(ext);
}
bool FindIconPath(const BString& pattern, BString& result)
{
	static BStringArray dirs;
	if (dirs.empty())
	{
		BString xdg_data_dirs = getenv("XDG_DATA_DIRS");
		if (xdg_data_dirs.size())
		{
			xdg_data_dirs.split(dirs, ':');
		}
		dirs.append("/usr/local/share");
		dirs.append("/usr/share");
		BString localPath;
		localPath << BApplication::homePath() << "/.local/share";
		if (BFolder::Exist(localPath))
		{
			dirs.prepend(localPath);
		}
	}

	static BString theme;
	static BString gtk3_path;
	if (gtk3_path.empty())
	{
		gtk3_path = BApplication::homePath();
		gtk3_path << "/.config/gtk-3.0/settings.ini";
		if (BFile::Exist(gtk3_path))
		{
			BString text;
			BFile::Load(gtk3_path, text);
			BString line;
			int pos = 0;
			while (pos < text.size())
			{
				pos = text.line(line, pos);
				int index = line.find("gtk-icon-theme-name=");
				if (index < line.size())
				{
					line.truncate(index + 20);
					theme = line;
					break;
				}
			}
		}
	}

	BString theme_path;
	if (theme.size())
	{
		IconTheme theme_info;
		for (int i = 0; i < dirs.size(); i++)
		{
			theme_path.reset();
			theme_path << dirs[i] << "/icons";
			theme_path << '/' << theme;
			if (!BFolder::Exist(theme_path))
				continue;

			if (!read_theme_index(theme_path, theme_info))
				continue;

			BStringArray paths = theme_info.directories.split(',');
			for (int i = 0; i < paths.size(); i++)
			{
				BString dir_path;
				dir_path << theme_path << '/' << paths[i];
				if (BFolder::Search(dir_path, pattern, result))
					return true;
			}
		}
	}

	for (int i = 0; i < dirs.size(); i++)
	{
		theme_path.reset();
		theme_path << dirs[i] << "/icons";
		if (BFolder::Search(theme_path, pattern, result))
			return true;
	}

	return BFolder::Search("/usr/share/pixmaps", pattern, result);
}

void InitSystemDisks()
{
	if (disks.empty())
	{
		BDisk *root = new BDisk();
		disk_member(root)->type = BDisk::Root;
		root->setName("/");
		disks.append(root);

		passwd *pwd = getpwuid(getuid());
		BDisk *home = new BDisk();
		home->setName("Home");
		disk_member(home)->path = pwd->pw_dir;
		disk_member(home)->type = BDisk::Symbol;
		disks.append(home);

		BString mountPath("/media/");
		mountPath += pwd->pw_name;
		BFolder folder(mountPath);
		if (folder.open())
		{
			for (int i = 0; i < folder.entryCount(); i++)
			{
				BEntry *entry = folder.entry(i);
				BDisk *disk = new BDisk();
				disk->setName(entry->name());
				disk_member(disk)->path = entry->path();
				disk_member(disk)->type = BDisk::Symbol;
				disks.append(disk);
			}
		}
	}
}
void InitSystemScreens()
{
	if (screens.empty() && app_display)
	{
		int num = XScreenCount(app_display);
		for (int i = 0; i < num; i++)
		{
			Screen *scn = XScreenOfDisplay(app_display, i);
			BScreen *screen = new BScreen();
			screen->setName(i);
			screen_member(screen)->info = XDisplayName(0);
			screen_member(screen)->number = i;
			if (scn)
			{
				screen_member(screen)->pos.x() = 0;
				screen_member(screen)->pos.y() = 0;
				screen_member(screen)->size.setWidth(XWidthOfScreen(scn));
				screen_member(screen)->size.setHeight(XHeightOfScreen(scn));
				screen_member(screen)->pixelBits = 32;
			}
			else
			{
				screen_member(screen)->pos.x() = 0;
				screen_member(screen)->pos.y() = 0;
				screen_member(screen)->size.setWidth(0);
				screen_member(screen)->size.setHeight(0);
				screen_member(screen)->pixelBits = 0;
			}
			screens.append(screen);
		}
	}
}
void InitSystemNetworks()
{
	if (networks.empty())
	{
	}
}
int BSystem::GetCupCount()
{
	static int CpuNumber = 0;

	return CpuNumber;
}
BLong BSystem::GetMemorySize()
{
	return 0;
}

BStringList BSystem::GetSerialPortNames()
{
	BStringList portlst;
	return portlst;
}

bool BSystem::SetClippedText(const BString &text)
{
	app_clipBoard = text;
	if (IWindow *window = app_windows.first())
	{
		Atom selection = XInternAtom(app_display, "CLIPBOARD", False);
		XSetSelectionOwner(app_display, selection, window->hwnd, CurrentTime);
		XGetSelectionOwner(app_display, selection);
	}
	return true;
}
bool BSystem::GetClippedText(BString &text)
{
	if (IWindow *window = app_windows.first())
	{
		Atom selection = XInternAtom(app_display, "CLIPBOARD", False);
		Window owner = XGetSelectionOwner(app_display, selection);
		if (owner && owner != window->hwnd)
		{
			app_clipBoard.clear();
			Atom property = XInternAtom(app_display, "text", False);
			XConvertSelection(app_display, selection, XA_STRING, property, window->hwnd, CurrentTime);
			XFlush(app_display);

			BReal tick = bTime();
			while (app_clipBoard.empty() && bTime() - tick < 0.1)
			{
				App_CycleBegin();
				App_Event();
				App_Signal();
				App_Update();
				App_Frame();
				App_CycleEnd();
			}
		}
	}
	if (const char *cstr = app_clipBoard)
	{
		text = cstr;
	}
	else if (app_clipBoard.is<BString>())
	{
		text = (const BString &)app_clipBoard;
	}
	return true;
}

void BSystem::SetClippedValue(const BValue &value)
{
	Atom clipboard = XInternAtom(app_display, "CLIPBOARD", False);
	app_clipBoard = value;
}
const BValue &BSystem::GetClippedValue()
{
	return app_clipBoard;
}
void BSystem::ClearClippedValue()
{
	app_clipBoard.clear();
}

bool BSystem::KeyState(Key ckey)
{
	char keys[32];
	XQueryKeymap(app_display, keys);
	KeySym keysym = 0;
	if (ckey == Key_LAlt)
		keysym = XK_Alt_L;
	else if (ckey == Key_RAlt)
		keysym = XK_Alt_R;
	else if (ckey == Key_LCtrl)
		keysym = XK_Control_L;
	else if (ckey == Key_RCtrl)
		keysym = XK_Control_R;
	else if (ckey == Key_LShift)
		keysym = XK_Shift_L;
	else if (ckey == Key_RShift)
		keysym = XK_Shift_L;
	if (keysym)
	{
		KeyCode code = XKeysymToKeycode(app_display, keysym);
		return (keys[code / 8] & (1 << (code % 8)));
	}
	if (ckey == Key_Alt)
	{
		KeyCode lalt = XKeysymToKeycode(app_display, XK_Alt_L);
		KeyCode ralt = XKeysymToKeycode(app_display, XK_Alt_R);
		return (keys[lalt / 8] & (1 << (lalt % 8))) || (keys[ralt / 8] & (1 << (ralt % 8)));
	}
	if (ckey == Key_Ctrl)
	{
		KeyCode lctrl = XKeysymToKeycode(app_display, XK_Control_L);
		KeyCode rctrl = XKeysymToKeycode(app_display, XK_Control_R);
		return (keys[lctrl / 8] & (1 << (lctrl % 8))) || (keys[rctrl / 8] & (1 << (rctrl % 8)));
	}
	if (ckey == Key_Shift)
	{
		KeyCode lshift = XKeysymToKeycode(app_display, XK_Shift_L);
		KeyCode rshift = XKeysymToKeycode(app_display, XK_Shift_R);
		return (keys[lshift / 8] & (1 << (lshift % 8))) || (keys[rshift / 8] & (1 << (rshift % 8)));
	}
	return false;
}

BImage *BSystem::EntryImage(const BString &filePath)
{
	const BString& mime = GetMimeMap(filePath);
	static BMap<BString, BImageHolder> imageMap;
	auto it = imageMap.find(mime);
	if (it.valid())
		return *it;

	BString pattern;
	pattern << '^' << mime << "\\.(?:png|svg|xpm)$";

	BString icon_path;
	FindIconPath(pattern, icon_path);
	if (icon_path.size())
	{
		BImage* image = new BImage(icon_path);
		imageMap[mime] = image;
		return image;
	}
	return 0;
}
BIcon *BSystem::EntryIcon(const BString &filePath)
{
	const BString& mime = GetMimeMap(filePath);
	static BMap<BString, BIconHolder> iconMap;
	auto it = iconMap.find(mime);
	if (it.valid())
		return *it;

	BString pattern;
	pattern << '^' << mime << "\\.(?:png|svg|xpm)$";

	BString icon_path;
	FindIconPath(pattern, icon_path);
	if (icon_path.size())
	{
		BIcon* icon = new BIcon(icon_path);
		iconMap[mime] = icon;
		return icon;
	}
	return 0;
}

BImage *BSystem::TypedImage(StyleImage name)
{
	return 0;
}
BIcon *BSystem::TypedIcon(StyleIcon name)
{
	int sign = 0;
	switch (name)
	{
	case Icon_Application:
		// sign = IDI_WINLOGO;
		break;
	case Icon_About:
		// sign = IDI_APPLICATION;
		break;
	case Icon_Critical:
		// sign = IDI_ERROR;
		break;
	case Icon_Information:
		// sign = IDI_INFORMATION;
		break;
	case Icon_Question:
		// sign = IDI_QUESTION;
		break;
	case Icon_Warning:
		// sign = IDI_WARNING;
		break;
	default:
		return 0;
	}

	static BMap<int, BIconHolder> typedIconMap;
	// auto it = typedIconMap.find(hIcon);
	// if (it.valid())
	//	return *it;
	BIcon *icon = 0;
	// typedIconMap[hIcon] = icon;
	return icon;
}

#endif

#ifdef _WIN32
#include <Windows.h>
#define far
#define near
#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")

void InitSystemDisks()
{
	if (disks.empty())
	{
		TCHAR buffer[MAX_PATH] = {};
		GetLogicalDriveStrings(MAX_PATH, buffer);
		TCHAR *name = buffer;
		while (*name != 0)
		{
			int dtype = GetDriveType(name);
			BDisk::Type type = BDisk::Unknown;
			switch (dtype)
			{
			case DRIVE_REMOVABLE:
				type = BDisk::Removable;
				break;
			case DRIVE_FIXED:
				type = BDisk::Fixed;
				break;
			case DRIVE_REMOTE:
				type = BDisk::Remote;
				break;
			case DRIVE_CDROM:
				type = BDisk::CDRom;
				break;
			case DRIVE_RAMDISK:
				type = BDisk::RamDisk;
				break;
			default:
				break;
			}
			char cstr[MAX_PATH];
			bWcsToMbs(name, cstr);
			BDisk *disk = new BDisk();
			disk->setName(cstr);
			disk_member(disk)->type = type;
			DWORD &a = disk_member(disk)->sectorsPerCluster;
			DWORD &b = disk_member(disk)->bytesPerSector;
			DWORD &c = disk_member(disk)->numberOfFreeClusters;
			DWORD &d = disk_member(disk)->totalNumberOfClusters;
			GetDiskFreeSpace(name, &a, &b, &c, &d);
			disks.append(disk);
			name += lstrlen(name) + 1;
		}
	}
}
void InitSystemScreens()
{
	if (screens.empty())
	{
		int count = ::GetSystemMetrics(SM_CMONITORS);
		for (int i = 0; i < count; i++)
		{
			DISPLAY_DEVICEA device;
			device.cb = sizeof(device);
			if (!::EnumDisplayDevicesA(NULL, i, &device, 0)) // Do not track devices used for remote access (Terminal Services pseudo-displays, etc.)
				break;

			if (device.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) // Only return display devices that are attached to the desktop
				continue;

			if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
				continue;

			DEVMODEA deviceMode;
			if (!EnumDisplaySettingsA(device.DeviceName, ENUM_CURRENT_SETTINGS, &deviceMode))
			{
				continue;
			}
			BScreen *screen = new BScreen();
			screen->setName(device.DeviceName);
			screen_member(screen)->info = device.DeviceString;
			screen_member(screen)->number = i;
			if ((deviceMode.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != 0)
			{
				screen_member(screen)->pos.x() = deviceMode.dmPosition.x;
				screen_member(screen)->pos.y() = deviceMode.dmPosition.y;
				screen_member(screen)->size.setWidth(deviceMode.dmPelsWidth);
				screen_member(screen)->size.setHeight(deviceMode.dmPelsHeight);
				screen_member(screen)->pixelBits = deviceMode.dmBitsPerPel;
			}
			else
			{
				screen_member(screen)->pos.x() = 0;
				screen_member(screen)->pos.y() = 0;
				screen_member(screen)->size.setWidth(0);
				screen_member(screen)->size.setHeight(0);
				screen_member(screen)->pixelBits = 0;
			}
			screens.append(screen);
		}
	}
}
void InitSystemNetworks()
{
	if (networks.empty())
	{
		PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
		unsigned long adapter_size = sizeof(IP_ADAPTER_INFO);
		int ret = GetAdaptersInfo(pIpAdapterInfo, &adapter_size);

		if (ret == ERROR_BUFFER_OVERFLOW)
		{
			delete pIpAdapterInfo;
			pIpAdapterInfo = (PIP_ADAPTER_INFO) new BYTE[adapter_size];
			ret = GetAdaptersInfo(pIpAdapterInfo, &adapter_size);
		}

		if (ret == ERROR_SUCCESS)
		{
			BString name;
			int cardIndex = 0;
			while (pIpAdapterInfo)
			{
				name.reset();
				name << "eth" << cardIndex;
				BNetwork *network = new BNetwork(name);
				network_member(network)->cardIndex = ++cardIndex;
				network_member(network)->adapterName = pIpAdapterInfo->AdapterName;
				network_member(network)->description = pIpAdapterInfo->Description;
				networks.append(network);

				PIP_ADDR_STRING pIpAddr = &(pIpAdapterInfo->IpAddressList);
				while (pIpAddr)
				{
					network_member(network)->ipAddress << pIpAddr->IpAddress.String << '\n';
					network_member(network)->ipMask << pIpAddr->IpMask.String << '\n';
					pIpAddr = pIpAddr->Next;
				}
				network_member(network)->ipAddress -= '\n';
				network_member(network)->ipMask -= '\n';

				PIP_ADDR_STRING pGatewayAddr = &(pIpAdapterInfo->GatewayList);
				while (pGatewayAddr)
				{
					network_member(network)->gateway << pGatewayAddr->IpAddress.String << '\n';
					pGatewayAddr = pGatewayAddr->Next;
				}
				network_member(network)->gateway -= '\n';

				PIP_ADDR_STRING pDhcpAddr = &(pIpAdapterInfo->DhcpServer);
				while (pDhcpAddr)
				{
					network_member(network)->dhcpServer << pDhcpAddr->IpAddress.String << '\n';
					pDhcpAddr = pDhcpAddr->Next;
				}
				network_member(network)->dhcpServer -= '\n';

				char local_mac[128] = {0};
				int char_index = 0;
				for (unsigned int i = 0; i < pIpAdapterInfo->AddressLength; i++)
				{
					char temp_str[10] = {0};
					sprintf(temp_str, "%02X-", pIpAdapterInfo->Address[i]);
					strcpy(local_mac + char_index, temp_str);
					char_index += 3;
				}
				local_mac[17] = '\0';
				network_member(network)->macAddress = local_mac;
				pIpAdapterInfo = pIpAdapterInfo->Next;
			}
		}

		if (pIpAdapterInfo)
			delete pIpAdapterInfo;
	}
}

BImage *ExtractSytemImage(HICON hIcon)
{
	ICONINFO info = {0};
	if (!::GetIconInfo(hIcon, &info))
		return 0;
	BITMAP bitmap = {0};
	if (GetObject(info.hbmColor, sizeof(BITMAP), &bitmap) == 0)
	{
		DeleteObject(info.hbmColor);
		DeleteObject(info.hbmMask);
		return 0;
	}
	if (bitmap.bmBitsPixel == 32)
	{
		LONG size = bitmap.bmWidth * bitmap.bmHeight;
		bitmap.bmWidthBytes;
		BImage *image = new BImage(bitmap.bmWidth, bitmap.bmHeight, Format_RGBA);
		BColor *colors = (BColor *)image->pixels()->data();
		::GetBitmapBits(info.hbmColor, size * sizeof(BColor), colors);
		for (int i = 0; i < size; i++)
		{
			BColor &c = colors[i];
			bSwap(c.r(), c.b());
		}
		return image;
	}
	DeleteObject(info.hbmColor);
	DeleteObject(info.hbmMask);
	return 0;
}

int BSystem::GetCupCount()
{
	static int CpuNumber = 0;
	SYSTEM_INFO SystemInfo;
	GetSystemInfo(&SystemInfo);
	CpuNumber = SystemInfo.dwNumberOfProcessors;
	return CpuNumber;
}

BLong BSystem::GetMemorySize()
{
	MEMORYSTATUSEX statusex;
	statusex.dwLength = sizeof(statusex);
	if (GlobalMemoryStatusEx(&statusex))
	{
		return statusex.ullTotalPhys;
	}
	return 0;
}

BStringList BSystem::GetSerialPortNames()
{
	BStringList portlst;
	HKEY hkey = 0;
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_READ, &hkey) != ERROR_SUCCESS)
	{
		return portlst;
	}
	wchar_t valueName[256];
	DWORD nameSize = 256;
	wchar_t data[256];
	DWORD dataSize = 256;
	DWORD type = 0;
	int i = 0;
	while (ERROR_NO_MORE_ITEMS != RegEnumValueW(hkey, i++, valueName, &nameSize, 0, &type, (BYTE *)data, &dataSize))
	{
		char cstr[256];
		bWcsToMbs(data, cstr);
		portlst.append(cstr);
		nameSize = 256;
		dataSize = 256;
	}
	RegCloseKey(hkey);
	return portlst;
}

bool BSystem::SetClippedText(const BString &text)
{
	if (!OpenClipboard(NULL))
		return false;

	if (!EmptyClipboard())
		return false;

	const char *cstr = text.cstr();
	int wlen = bMbsToWcs(text.cstr(), 0);
	wchar_t *wstr = new wchar_t[wlen];
	bMbsToWcs(text.cstr(), wstr);
	int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
	HGLOBAL hMen = GlobalAlloc(GMEM_MOVEABLE, len + 1);
	if (!hMen)
	{
		CloseClipboard();
		delete wstr;
		return false;
	}

	if (LPSTR lpStr = (LPSTR)GlobalLock(hMen))
	{
		WideCharToMultiByte(CP_ACP, 0, wstr, -1, lpStr, len, NULL, NULL);
		GlobalUnlock(hMen);
		SetClipboardData(CF_TEXT, hMen);
	}

	CloseClipboard();
	delete wstr;
	return true;
}
bool BSystem::GetClippedText(BString &text)
{
	if (OpenClipboard(0))
	{
		UINT format = 0;
		while (1)
		{
			format = EnumClipboardFormats(format);
			if (format == CF_TEXT)
			{
				HGLOBAL hMem = GetClipboardData(format);
				SIZE_T dwSize = GlobalSize(hMem);
				char *cstr = (char *)::GlobalLock(hMem);
				if (cstr)
				{
					text = cstr;
					break;
				}
				GlobalUnlock(hMem);
			}
			if (format == 0)
				break;
		}
		CloseClipboard();
		if (text.hasUtf(16))
		{
			int wlen = MultiByteToWideChar(CP_ACP, 0, text.cstr(), -1, 0, 0);
			wchar_t *wstr = new wchar_t[wlen];
			MultiByteToWideChar(CP_ACP, 0, text.cstr(), -1, wstr, wlen);
			int len = bWcsToMbs(wstr, 0);
			char *cstr = new char[len];
			bWcsToMbs(wstr, cstr);
			text = cstr;
			delete wstr;
			delete cstr;
		}
		return text.size();
	}
	return false;
}

void BSystem::SetClippedValue(const BValue &value)
{
	app_clipBoard = value;
}
const BValue &BSystem::GetClippedValue()
{
	return app_clipBoard;
}
void BSystem::ClearClippedValue()
{
	app_clipBoard.clear();
}

bool BSystem::KeyState(Key ckey)
{
	int state = 0;
	if (ckey == Key_LSys)
		state = GetKeyState(VK_LWIN);
	else if (ckey == Key_RSys)
		state = GetKeyState(VK_RWIN);
	else if (ckey == Key_LButton)
		state = GetKeyState(VK_LBUTTON);
	else if (ckey == Key_MButton)
		state = GetKeyState(VK_MBUTTON);
	else if (ckey == Key_RButton)
		state = GetKeyState(VK_RBUTTON);
	else if (ckey == Key_Alt)
		state = GetKeyState(VK_MENU);
	else if (ckey == Key_LAlt)
		state = GetKeyState(VK_LMENU);
	else if (ckey == Key_RAlt)
		state = GetKeyState(VK_RMENU);
	else if (ckey == Key_Ctrl)
		state = GetKeyState(VK_CONTROL);
	else if (ckey == Key_LCtrl)
		state = GetKeyState(VK_LCONTROL);
	else if (ckey == Key_RCtrl)
		state = GetKeyState(VK_RCONTROL);
	else if (ckey == Key_Shift)
		state = GetKeyState(VK_SHIFT);
	else if (ckey == Key_LShift)
		state = GetKeyState(VK_LSHIFT);
	else if (ckey == Key_RShift)
		state = GetKeyState(VK_RSHIFT);
	return state < 0;
}

BImage *BSystem::EntryImage(const BString &filePath)
{
	SHFILEINFO finfo;
	ZeroMemory(&finfo, sizeof(SHFILEINFO));
	if (filePath.contain('/'))
	{
		BString path = filePath;
		path.replace("//", '/');
		path.replace('/', '\\');
		wchar_t ustr[256];
		bMbsToWcs(path.cstr(), ustr);
		SHGetFileInfoW(ustr, 0, &finfo, sizeof(finfo), SHGFI_ICON | SHGFI_LARGEICON);
	}
	else
	{
		wchar_t ustr[256];
		bMbsToWcs(filePath.cstr(), ustr);
		SHGetFileInfoW(ustr, 0, &finfo, sizeof(finfo), SHGFI_ICON | SHGFI_LARGEICON);
	}
	if (finfo.iIcon == 0)
		return 0;

	static BMap<int, BImageHolder> entryImageMap;
	auto it = entryImageMap.find(finfo.iIcon);
	if (it.valid())
		return *it;

	BImage *image = ExtractSytemImage(finfo.hIcon);
	entryImageMap[finfo.iIcon] = image;
	return image;
}
BIcon *BSystem::EntryIcon(const BString &filePath)
{
	SHFILEINFO finfo;
	ZeroMemory(&finfo, sizeof(SHFILEINFO));
	if (filePath.contain('/'))
	{
		BString path = filePath;
		path.replace("//", '/');
		path.replace('/', '\\');
		wchar_t ustr[256];
		bMbsToWcs(path.cstr(), ustr);
		SHGetFileInfoW(ustr, 0, &finfo, sizeof(finfo), SHGFI_ICON | SHGFI_LARGEICON);
	}
	else
	{
		wchar_t ustr[256];
		bMbsToWcs(filePath.cstr(), ustr);
		SHGetFileInfoW(ustr, 0, &finfo, sizeof(finfo), SHGFI_ICON | SHGFI_LARGEICON);
	}
	if (finfo.iIcon == 0)
		return 0;

	static BMap<int, BIconHolder> entryIconMap;
	auto it = entryIconMap.find(finfo.iIcon);
	if (it.valid())
		return *it;

	BImage *image = ExtractSytemImage(finfo.hIcon);
	if (image == 0)
		return 0;

	BIcon *icon = new BIcon(image);
	entryIconMap[finfo.iIcon] = icon;
	return icon;
}

BImage *BSystem::TypedImage(StyleImage name)
{
	LPCWSTR sign = 0;
	switch (name)
	{
	case Icon_Application:
		sign = IDI_WINLOGO;
		break;
	case Icon_About:
		sign = IDI_APPLICATION;
		break;
	case Icon_Critical:
		sign = IDI_ERROR;
		break;
	case Icon_Information:
		sign = IDI_INFORMATION;
		break;
	case Icon_Question:
		sign = IDI_QUESTION;
		break;
	case Icon_Warning:
		sign = IDI_WARNING;
		break;
	default:
		return 0;
	}
	HICON hIcon = LoadIconW(0, sign);
	static BMap<HICON, BImageHolder> typedImageMap;
	auto it = typedImageMap.find(hIcon);
	if (it.valid())
		return *it;

	BImage *image = ExtractSytemImage(hIcon);
	typedImageMap[hIcon] = image;
	return image;
}
BIcon *BSystem::TypedIcon(StyleIcon name)
{
	LPCWSTR sign = 0;
	switch (name)
	{
	case Icon_Application:
		sign = IDI_WINLOGO;
		break;
	case Icon_About:
		sign = IDI_APPLICATION;
		break;
	case Icon_Critical:
		sign = IDI_ERROR;
		break;
	case Icon_Information:
		sign = IDI_INFORMATION;
		break;
	case Icon_Question:
		sign = IDI_QUESTION;
		break;
	case Icon_Warning:
		sign = IDI_WARNING;
		break;
	default:
		return 0;
	}
	HICON hIcon = LoadIconW(0, sign);
	static BMap<HICON, BIconHolder> typedIconMap;
	auto it = typedIconMap.find(hIcon);
	if (it.valid())
		return *it;

	BImage *image = ExtractSytemImage(hIcon);
	if (image == 0)
		return 0;

	BIcon *icon = new BIcon(image);
	typedIconMap[hIcon] = icon;
	return icon;
}

HBITMAP CopyScreenToBitmap(LPRECT lpRect)
{
	HDC hScrDC, hMemDC;
	HBITMAP hBitmap, hOldBitmap;
	int nX, nY, nX2, nY2;
	int nWidth, nHeight;
	int xScrn, yScrn;
	if (IsRectEmpty(lpRect))
	{
		return NULL;
	}

	hScrDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);

	hMemDC = CreateCompatibleDC(hScrDC);

	nX = lpRect->left;
	nY = lpRect->top;
	nX2 = lpRect->right;
	nY2 = lpRect->bottom;

	xScrn = GetDeviceCaps(hScrDC, HORZRES);
	yScrn = GetDeviceCaps(hScrDC, VERTRES);

	if (nX < 0)
		nX = 0;
	if (nY < 0)
		nY = 0;
	if (nX2 > xScrn)
		nX2 = xScrn;
	if (nY2 > yScrn)
		nY2 = yScrn;
	nWidth = nX2 - nX;
	nHeight = nY2 - nY;

	hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);

	hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);

	BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);

	hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);

	DeleteDC(hScrDC);
	DeleteDC(hMemDC);

	return hBitmap;
}

#endif

int BSystem::RefreshScreens()
{
	screens.reset();
	InitSystemScreens();
	return screens.size();
}
int BSystem::GetScreenCount()
{
	InitSystemScreens();
	return screens.size();
}
BScreen *BSystem::GetScreen(int index)
{
	InitSystemScreens();
	return screens(index);
}
BScreen *BSystem::GetScreen(const BPoint &pos)
{
	InitSystemScreens();
	for (int i = 0; i < screens.size(); i++)
	{
		BScreen *screen = screens[i];
		BRect rect(screen->pos(), screen->size());
		if (rect.contain(pos))
			return screen;
	}
	return 0;
}
BScreen *BSystem::GetScreen(const BRect &rect)
{
	InitSystemScreens();
	for (int i = 0; i < screens.size(); i++)
	{
		BScreen *screen = screens[i];
		BRect rect(screen->pos(), screen->size());
		if (rect.contain(rect.pos()))
			return screen;
	}
	return 0;
}

int BSystem::RefreshDisks()
{
	disks.reset();
	InitSystemDisks();
	return disks.size();
}
int BSystem::GetDiskCount()
{
	InitSystemDisks();
	return disks.size();
}
BDisk *BSystem::GetDisk(int index)
{
	InitSystemDisks();
	return disks(index);
}

int BSystem::RefreshNetworks()
{
	networks.reset();
	InitSystemNetworks();
	return networks.size();
}
int BSystem::GetNetworkCount()
{
	InitSystemNetworks();
	return networks.size();
}
BNetwork *BSystem::GetNetWork(int index)
{
	InitSystemNetworks();
	return networks(index);
}

BTime BSystem::LocalTime()
{
	time_t t;
	::time(&t);
	tm *ptm = localtime(&t);
	BTime time(ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
	return time;
}
BDate BSystem::LocalDate()
{
	time_t t;
	::time(&t);
	tm *ptm = localtime(&t);
	BDate date(ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday);
	return date;
}

bool BSystem::LocalTime(BDate &date, BTime &time)
{
	time_t t;
	::time(&t);
	if (tm *ptm = localtime(&t))
	{
		date.set(ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday);
		time.set(ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
		return true;
	}
	return false;
}

BString BSystem::FontPath()
{
#ifdef _WIN32
	return BString("C:/Windows/Fonts");
#endif
#ifdef linux
	return BString("/usr/share/fonts");
#endif
	return BString();
}

BColor HexFmtColor(const char* cstr)
{
	int size = (int)strlen(cstr);
	if (cstr[0] == '#')
	{
		size--;
		cstr++;
	}
	BColor color;
	if (size == 6)
	{
		color.r() = bHexToInt(cstr + 0, 2);
		color.g() = bHexToInt(cstr + 2, 2);
		color.b() = bHexToInt(cstr + 4, 2);
		color.a() = 255;
	}
	if (size == 8)
	{
		color.r() = bHexToInt(cstr + 0, 2);
		color.g() = bHexToInt(cstr + 2, 2);
		color.b() = bHexToInt(cstr + 4, 2);
		color.a() = bHexToInt(cstr + 6, 2);
	}
	return color;
}
const BMap<BString, BColor>& Global_Color_Map()
{
	static BMap<BString, BColor> colorMap;
	if (colorMap.empty())
	{
		colorMap["transparent"] = BColor();
		colorMap["aliceblue"] = HexFmtColor("#F0F8FF");
		colorMap["antiquewhite"] = HexFmtColor("#FAEBD7");
		colorMap["aqua"] = HexFmtColor("#00FFFF");
		colorMap["aquamarine"] = HexFmtColor("#7FFFD4");
		colorMap["azure"] = HexFmtColor("#F0FFFF");
		colorMap["beige"] = HexFmtColor("#F5F5DC");
		colorMap["bisque"] = HexFmtColor("#FFE4C4");
		colorMap["black"] = HexFmtColor("#000000");
		colorMap["blanchedalmond"] = HexFmtColor("#FFEBCD");
		colorMap["blue"] = HexFmtColor("#0000FF");
		colorMap["blueviolet"] = HexFmtColor("#8A2BE2");
		colorMap["brown"] = HexFmtColor("#A52A2A");
		colorMap["burlywood"] = HexFmtColor("#DEB887");
		colorMap["cadetblue"] = HexFmtColor("#5F9EA0");
		colorMap["chartreuse"] = HexFmtColor("#7FFF00");
		colorMap["chocolate"] = HexFmtColor("#D2691E");
		colorMap["coral"] = HexFmtColor("#FF7F50");
		colorMap["cornflowerblue"] = HexFmtColor("#6495ED");
		colorMap["cornsilk"] = HexFmtColor("#FFF8DC");
		colorMap["crimson"] = HexFmtColor("#DC143C");
		colorMap["cyan"] = HexFmtColor("#00FFFF");
		colorMap["darkblue"] = HexFmtColor("#00008B");
		colorMap["darkcyan"] = HexFmtColor("#008B8B");
		colorMap["darkgoldenrod"] = HexFmtColor("#B8860B");
		colorMap["darkgray"] = HexFmtColor("#A9A9A9");
		colorMap["darkgreen"] = HexFmtColor("#006400");
		colorMap["darkkhaki"] = HexFmtColor("#BDB76B");
		colorMap["darkmagenta"] = HexFmtColor("#8B008B");
		colorMap["darkolivegreen"] = HexFmtColor("#556B2F");
		colorMap["darkorange"] = HexFmtColor("#FF8C00");
		colorMap["darkorchid"] = HexFmtColor("#9932CC");
		colorMap["darkred"] = HexFmtColor("#8B0000");
		colorMap["darksalmon"] = HexFmtColor("#E9967A");
		colorMap["darkseagreen"] = HexFmtColor("#8FBC8F");
		colorMap["darkslateblue"] = HexFmtColor("#483D8B");
		colorMap["darkslategray"] = HexFmtColor("#2F4F4F");
		colorMap["darkturquoise"] = HexFmtColor("#00CED1");
		colorMap["darkviolet"] = HexFmtColor("#9400D3");
		colorMap["deeppink"] = HexFmtColor("#FF1493");
		colorMap["deepskyblue"] = HexFmtColor("#00BFFF");
		colorMap["dimgray"] = HexFmtColor("#696969");
		colorMap["dodgerblue"] = HexFmtColor("#1E90FF");
		colorMap["feldspar"] = HexFmtColor("#D19275");
		colorMap["firebrick"] = HexFmtColor("#B22222");
		colorMap["floralwhite"] = HexFmtColor("#FFFAF0");
		colorMap["forestgreen"] = HexFmtColor("#228B22");
		colorMap["fuchsia"] = HexFmtColor("#FF00FF");
		colorMap["gainsboro"] = HexFmtColor("#DCDCDC");
		colorMap["ghostwhite"] = HexFmtColor("#F8F8FF");
		colorMap["gold"] = HexFmtColor("#FFD700");
		colorMap["goldenrod"] = HexFmtColor("#DAA520");
		colorMap["gray"] = HexFmtColor("#808080");
		colorMap["green"] = HexFmtColor("#008000");
		colorMap["greenyellow"] = HexFmtColor("#ADFF2F");
		colorMap["honeydew"] = HexFmtColor("#F0FFF0");
		colorMap["hotpink"] = HexFmtColor("#FF69B4");
		colorMap["indianred"] = HexFmtColor("#CD5C5C");
		colorMap["indigo"] = HexFmtColor("#4B0082");
		colorMap["ivory"] = HexFmtColor("#FFFFF0");
		colorMap["khaki"] = HexFmtColor("#F0E68C");
		colorMap["lavender"] = HexFmtColor("#E6E6FA");
		colorMap["lavenderblush"] = HexFmtColor("#FFF0F5");
		colorMap["lawngreen"] = HexFmtColor("#7CFC00");
		colorMap["lemonchiffon"] = HexFmtColor("#FFFACD");
		colorMap["lightblue"] = HexFmtColor("#ADD8E6");
		colorMap["lightcoral"] = HexFmtColor("#F08080");
		colorMap["lightcyan"] = HexFmtColor("#E0FFFF");
		colorMap["lightgoldenrodyellow"] = HexFmtColor("#FAFAD2");
		colorMap["lightgrey"] = HexFmtColor("#D3D3D3");
		colorMap["lightgreen"] = HexFmtColor("#90EE90");
		colorMap["lightpink"] = HexFmtColor("#FFB6C1");
		colorMap["lightsalmon"] = HexFmtColor("#FFA07A");
		colorMap["lightseagreen"] = HexFmtColor("#20B2AA");
		colorMap["lightskyblue"] = HexFmtColor("#87CEFA");
		colorMap["lightslateblue"] = HexFmtColor("#8470FF");
		colorMap["lightslategray"] = HexFmtColor("#778899");
		colorMap["lightsteelblue"] = HexFmtColor("#B0C4DE");
		colorMap["lightyellow"] = HexFmtColor("#FFFFE0");
		colorMap["lime"] = HexFmtColor("#00FF00");
		colorMap["limegreen"] = HexFmtColor("#32CD32");
		colorMap["linen"] = HexFmtColor("#FAF0E6");
		colorMap["magenta"] = HexFmtColor("#FF00FF");
		colorMap["maroon"] = HexFmtColor("#800000");
		colorMap["mediumaquaMarine"] = HexFmtColor("#66CDAA");
		colorMap["mediumblue"] = HexFmtColor("#0000CD");
		colorMap["mediumorchid"] = HexFmtColor("#BA55D3");
		colorMap["mediumpurple"] = HexFmtColor("#9370D8");
		colorMap["mediumseagreen"] = HexFmtColor("#3CB371");
		colorMap["mediumslateblue"] = HexFmtColor("#7B68EE");
		colorMap["mediumspringgreen"] = HexFmtColor("#00FA9A");
		colorMap["mediumturquoise"] = HexFmtColor("#48D1CC");
		colorMap["mediumvioletred"] = HexFmtColor("#C71585");
		colorMap["midnightblue"] = HexFmtColor("#191970");
		colorMap["mintcream"] = HexFmtColor("#F5FFFA");
		colorMap["mistyrose"] = HexFmtColor("#FFE4E1");
		colorMap["moccasin"] = HexFmtColor("#FFE4B5");
		colorMap["navajowhite"] = HexFmtColor("#FFDEAD");
		colorMap["navy"] = HexFmtColor("#000080");
		colorMap["oldlace"] = HexFmtColor("#FDF5E6");
		colorMap["olive"] = HexFmtColor("#808000");
		colorMap["olivedrab"] = HexFmtColor("#6B8E23");
		colorMap["orange"] = HexFmtColor("#FFA500");
		colorMap["orangered"] = HexFmtColor("#FF4500");
		colorMap["orchid"] = HexFmtColor("#DA70D6");
		colorMap["palegoldenrod"] = HexFmtColor("#EEE8AA");
		colorMap["palegreen"] = HexFmtColor("#98FB98");
		colorMap["paleturquoise"] = HexFmtColor("#AFEEEE");
		colorMap["palevioletred"] = HexFmtColor("#D87093");
		colorMap["papayawhip"] = HexFmtColor("#FFEFD5");
		colorMap["peachpuff"] = HexFmtColor("#FFDAB9");
		colorMap["peru"] = HexFmtColor("#CD853F");
		colorMap["pink"] = HexFmtColor("#FFC0CB");
		colorMap["plum"] = HexFmtColor("#DDA0DD");
		colorMap["powderblue"] = HexFmtColor("#B0E0E6");
		colorMap["purple"] = HexFmtColor("#800080");
		colorMap["red"] = HexFmtColor("#FF0000");
		colorMap["rosybrown"] = HexFmtColor("#BC8F8F");
		colorMap["royalblue"] = HexFmtColor("#4169E1");
		colorMap["saddlebrown"] = HexFmtColor("#8B4513");
		colorMap["salmon"] = HexFmtColor("#FA8072");
		colorMap["sandybrown"] = HexFmtColor("#F4A460");
		colorMap["seagreen"] = HexFmtColor("#2E8B57");
		colorMap["seashell"] = HexFmtColor("#FFF5EE");
		colorMap["sienna"] = HexFmtColor("#A0522D");
		colorMap["silver"] = HexFmtColor("#C0C0C0");
		colorMap["skyblue"] = HexFmtColor("#87CEEB");
		colorMap["slateblue"] = HexFmtColor("#6A5ACD");
		colorMap["slategray"] = HexFmtColor("#708090");
		colorMap["snow"] = HexFmtColor("#FFFAFA");
		colorMap["springgreen"] = HexFmtColor("#00FF7F");
		colorMap["steelblue"] = HexFmtColor("#4682B4");
		colorMap["tan"] = HexFmtColor("#D2B48C");
		colorMap["teal"] = HexFmtColor("#008080");
		colorMap["thistle"] = HexFmtColor("#D8BFD8");
		colorMap["tomato"] = HexFmtColor("#FF6347");
		colorMap["turquoise"] = HexFmtColor("#40E0D0");
		colorMap["violet"] = HexFmtColor("#EE82EE");
		colorMap["violetred"] = HexFmtColor("#D02090");
		colorMap["wheat"] = HexFmtColor("#F5DEB3");
		colorMap["white"] = HexFmtColor("#FFFFFF");
		colorMap["whitesmoke"] = HexFmtColor("#F5F5F5");
		colorMap["yellow"] = HexFmtColor("#FFFF00");
		colorMap["yellowgreen"] = HexFmtColor("#9ACD32");
	}
	return colorMap;
}
const BColor& BSystem::NamedColor(const char* name)
{
	const BMap<BString, BColor>& colorMap = Global_Color_Map();
	return colorMap(name);
}
const BColor& BSystem::NamedColor(const BString& name)
{
	const BMap<BString, BColor>& colorMap = Global_Color_Map();
	return colorMap(name);
}
